<template>
    <el-container class="container">
        <el-main>
            <el-space direction="vertical" style="width: 100%" fill wrap>
                <el-card>
                    <div style="text-align: center">
                        <h1 class="animate-h1">123云盘直链签名测试工具</h1>
                    </div>
                    <div style="text-align: center">
                        <p class="text item">
                            123云盘在线直链签名测试工具（非官方），签名过程完全由前端进行（断网可用），不必担心您的签名过程被记录。</p>
                    </div>

                    <el-divider>
                        <el-icon>
                            <star-filled/>
                        </el-icon>
                    </el-divider>

                    <el-form :rules="rules">

                        <el-form-item :label="form.signMode ? '待签名的 URL' : '待效验的 URL'" prop="url" required>
                            <el-input v-model="form.url"
                                      placeholder="输入链接地址（短链与长链均可）"/>
                        </el-form-item>

                        <el-row :gutter="20">
                            <el-col :span="12" :xs="24" :sm="12">
                                <el-form-item  prop="key" required>
                                    <template #label>
                                        <span>鉴权密钥</span>
                                        <el-tooltip effect="dark" placement="bottom">
                                            <template #content>
                                                <div>
                                                    <el-text style="color: white">设置的鉴权密钥，可以在</el-text>
                                                    <el-text type="primary">
                                                        <a style="color:#409eff"
                                                           href="https://www.123pan.com/DirectLink" target="_blank">直链管理页面</a>
                                                    </el-text>
                                                    <el-text style="color: white">设置。</el-text>
                                                </div>
                                            </template>
                                            <el-icon>
                                                <QuestionFilled/>
                                            </el-icon>
                                        </el-tooltip>
                                    </template>
                                    <el-input
                                        v-model="form.key"
                                        type="password"
                                        placeholder="输入设置的鉴权密钥"
                                        show-password
                                    />
                                </el-form-item>
                            </el-col>
                            <el-col :span="12" :xs="24" :sm="12">
                                <el-form-item prop="uid" required>
                                    <template #label>
                                        <span>账号 UID</span>
                                        <el-tooltip effect="dark" placement="bottom">
                                            <template #content>
                                                <div>
                                                    <el-text style="color: white">云盘的用户ID，可以前往</el-text>
                                                    <el-text type="primary">
                                                        <a style="color:#409eff" href="https://www.123pan.com/Setting"
                                                           target="_blank">个人设置页面</a>
                                                    </el-text>
                                                    <el-text style="color: white">查看。</el-text>
                                                </div>
                                            </template>
                                            <el-icon>
                                                <QuestionFilled/>
                                            </el-icon>
                                        </el-tooltip>
                                    </template>
                                    <el-input
                                        v-model="form.uid"
                                        placeholder="输入账号 UID "
                                    />
                                </el-form-item>
                            </el-col>
                        </el-row>

                        <el-row :gutter="20">
                            <el-col :xs="24" :lg="3">
                                <el-form-item label="过期时间输入方式">
                                    <div style="display: flex;gap: 0.5rem;">
                                        <el-switch v-model="form.expireMode" @change="expireModeSwitch"/>
                                    </div>
                                </el-form-item>
                            </el-col>
                            <el-col :xs="24" :lg="21" v-show="form.expireMode">
                                <el-form-item :label="string.expireMode">
                                    <el-date-picker
                                        v-model="form.expireDate"
                                        type="datetime"
                                        placeholder="选择过期日期和时间"
                                        :shortcuts="constant.shortcuts"
                                    />
                                </el-form-item>
                            </el-col>
                            <el-col :xs="24" :lg="21" v-show="!form.expireMode">
                                <el-form-item :label="string.expireMode">
                                    <div style="display: flex;gap: 0.5rem;">
                                        <el-input-number v-model="form.expireTimestamp" :min="0" :max="9999999999"
                                                         @change="expireTimestampChange"/>
                                        <el-text class="mx-1">{{ string.expireTimestamp }}</el-text>
                                    </div>
                                </el-form-item>
                            </el-col>
                        </el-row>
                        <el-form-item>
                            <el-button type="primary" @click="onSubmit">{{
                                    form.signMode ? '签名' : '效验'
                                }}
                            </el-button>
                            <el-form-item :label="form.signMode?'签名模式':'效验模式'" style="margin-left: 0.5rem">
                                <div style="display: flex;gap: 0.5rem;">
                                    <el-switch v-model="form.signMode"/>
                                </div>
                            </el-form-item>
                        </el-form-item>

                    </el-form>

                    <el-collapse-transition>


                        <div v-show="constant.resultShow">

                            <el-form>
                                <el-collapse-transition>
                                    <el-form-item v-show="constant.warningShow">
                                        <el-alert
                                            :title="constant.warningTitle"
                                            type="warning"
                                            :description="constant.warningTip"
                                            :closable="false"
                                            show-icon

                                        />
                                    </el-form-item>
                                </el-collapse-transition>
                                <el-form-item label="签名结果">
                                    <el-input v-model="form.urlResult"
                                              placeholder="签名结果"
                                              :readonly="true"
                                              @click="resultInputBoxClick"
                                              ref="resultInputBox"
                                    />
                                </el-form-item>
                            </el-form>

                            <el-space direction="vertical" style="width: 100%">
                                <el-text tag="b" style="font-size: 1.5rem">离链接失效还有</el-text>
                                <el-text class="mx-1" type="danger" style="font-size: 2rem">
                                    {{ this.constant.countdownSecondText }}
                                </el-text>
                                <el-space :size="30" v-show="!constant.checkURLStatus">
                                    <el-text v-loading="true" style="transform: scale(0.5);"></el-text>
                                    <el-text>正在效验链接有效性......</el-text>
                                </el-space>
                                <el-space v-show="constant.checkURLStatus">
                                    <el-text tag="b" ref="URLStatusText"></el-text>
                                </el-space>
                            </el-space>
                        </div>
                    </el-collapse-transition>

                </el-card>
                <el-card>
                    <h1 style="text-align: center">代码生成 & 参考资源</h1>
                    <el-row :gutter="20">
                        <el-col :span="16" :xs="24">
                            <el-tabs>
                                <el-tab-pane label="Python">
                                    <div class="highlight-container">
                                        <highlightjs language="python" :code="getPythonCode()"/>
                                    </div>
                                </el-tab-pane>
                                <el-tab-pane label="NodeJS">
                                    <div class="highlight-container">
                                        <highlightjs language="javascript" :code="getJavascriptCode()"/>
                                    </div>
                                </el-tab-pane>
                                <el-tab-pane label="Java">
                                    <div class="highlight-container">
                                        <highlightjs language="java" :code="getJavaCode()"/>
                                    </div>
                                </el-tab-pane>
                                <el-tab-pane label="Go">
                                    <div class="highlight-container">
                                        <highlightjs language="go" :code="getGoCode()"/>
                                    </div>
                                </el-tab-pane>
                                <el-tab-pane label="PHP">
                                    <div class="highlight-container">
                                        <highlightjs language="php" :code="getPHPCode()"/>
                                    </div>
                                </el-tab-pane>
                            </el-tabs>
                        </el-col>
                        <el-col :span="8" :xs="24">
                            开发代码时的参考资源，与该页面签名算法引用资源。
                            <ul>
                                <li>官方链接签名说明：<a href="https://www.123pan.com/faq?problem=dev_guide"
                                                        target="_blank">点击前往</a></li>
                                <li>官方多种语言签名示例：<a href="https://gitee.com/pan123-git/123pan-link"
                                                            target="_blank">点击前往</a></li>
                            </ul>
                            开放接口示例：
                            <ul>
                                <li>简单Python示例：<a href="https://gitee.com/lyd-code/123pan-upload-python-example"
                                                      target="_blank">https://gitee.com/lyd-code/123pan-upload-python-example</a>、
                                    <a href="https://gitee.com/wojiaoyishang/123pan" target="_blank">https://gitee.com/wojiaoyishang/123pan</a>
                                </li>
                                <li>简单NodeJS示例：<a href="https://gitee.com/zaidu_jj/123pan-upload-example"
                                                      target="_blank">https://gitee.com/zaidu_jj/123pan-upload-example</a>
                                </li>
                                <li>简单PHP示例：<a href="https://gitee.com/itcolss/123pan-upload-php-example"
                                                   target="_blank">https://gitee.com/itcolss/123pan-upload-php-example</a>
                                </li>
                                <li>简单Java示例：<a href="https://www.yuque.com/feixiangnet/open" target="_blank">https://www.yuque.com/feixiangnet/open</a>
                                </li>
                            </ul>
                        </el-col>

                    </el-row>
                </el-card>
                <el-card style="position: relative;">
                    <el-row>
                        <el-space style="justify-content:center; width: 100%" wrap>
                            <el-link href="https://beian.miit.gov.cn/" target="_blank">浙ICP备2024126055号-1</el-link>
                            <el-text class="mx-1">·</el-text>
                            <el-link href="https://beian.mps.gov.cn/#/query/webSearch?code=33032602100621"
                                     target="_blank">
                                <el-image
                                    src="https://lovepikachu.top/wp-content/uploads/2024/10/5599d5944aa8340b47c9eab507b7dd34.png.webp"
                                    style="width: 20px; height: 20px"/>
                                浙公网安备33032602100621
                            </el-link>
                        </el-space>
                    </el-row>
                    <el-row>
                        <el-space style="justify-content:center; width: 100%">
                            <el-link href="https://icp.gov.moe/?keyword=20228205" target="_blank">萌ICP备20228205号
                            </el-link>
                            <el-text class="mx-1">·</el-text>
                            <el-image
                                src="https://lovepikachu.top/wp-content/uploads/2024/11/523eaa5d33d76245c9683bf159c25a23.png.webp"
                                style="width: 20px; height: 20px"/>
                            <el-link href="https://travel.moe/go.html"
                                     target="_blank">异次元之旅
                            </el-link>
                        </el-space>
                    </el-row>
                    <el-row>
                        <el-space style="justify-content:center; width: 100%">
                            <el-link href="https://lovepikachu.top" target="_blank">最爱皮卡丘博客</el-link>
                            <el-text class="mx-1">·</el-text>
                            <el-link href="https://lab.lovepikachu.top"
                                     target="_blank">秘密实验室
                            </el-link>
                        </el-space>
                    </el-row>
                    <el-image
                        src="https://lovepikachu.top/wp-content/uploads/2025/07/373cb41dae877e81b849f50418a22861.png.webp"
                        style="width: 80px; height: 80px; z-index: 1; position: absolute; right: 10px; bottom: 5px; opacity: 0.85"
                    />
                </el-card>
            </el-space>

        </el-main>
    </el-container>
</template>

<script>
import {QuestionFilled, StarFilled} from '@element-plus/icons-vue'
import crypto from 'crypto-js'
import {reactive, ref} from 'vue'

export default {
    components: {QuestionFilled, StarFilled},
    data() {
        return {
            rules:  reactive({
                url: [
                    { required: true, message: '请输入要签名/要效验的地址', trigger: 'blur' }
                ],
                key: [
                    { required: true, message: '鉴权密钥是必须的', trigger: 'blur' }
                ],
                uid: [
                    { required: true, message: '账号UID是必须的', trigger: 'blur' }
                ]
            }),
            constant: {
                shortcuts: [
                    {
                        text: '1分钟',
                        value: () => {
                            const date = new Date()
                            date.setMinutes(date.getMinutes() + 1)
                            return date
                        },
                    },
                    {
                        text: '5分钟',
                        value: () => {
                            const date = new Date()
                            date.setMinutes(date.getMinutes() + 5)
                            return date
                        },
                    },
                    {
                        text: '30分钟',
                        value: () => {
                            const date = new Date()
                            date.setMinutes(date.getMinutes() + 30)
                            return date
                        },
                    },
                    {
                        text: '一小时',
                        value: () => {
                            const date = new Date()
                            date.setHours(date.getHours() + 1)
                            return date
                        },
                    },
                    {
                        text: '一天',
                        value: () => {
                            const date = new Date()
                            date.setDate(date.getDate() + 1)
                            return date
                        },
                    },
                    {
                        text: '一星期',
                        value: () => {
                            const date = new Date()
                            date.setDate(date.getDate() + 7)
                            return date
                        },
                    },
                    {
                        text: '一个月',
                        value: () => {
                            const date = new Date()
                            date.setMonth(date.getMonth() + 1)
                            return date
                        },
                    },
                    {
                        text: '一年',
                        value: () => {
                            const date = new Date()
                            date.setFullYear(date.getFullYear() + 1)
                            return date
                        },
                    },
                ],
                resultShow: false,
                countdownSecond: 0,
                countdownSecondText: ref(''),
                countdownInterval: null,
                checkURLStatus: false,
                warningTitle: ref(null),
                warningTip: ref(null),
                warningShow: ref(false)
            },
            form: {
                url: ref(localStorage.getItem('url') || ''),
                key: ref(localStorage.getItem('key') || ''),
                uid: ref(localStorage.getItem('uid') || ''),
                expireMode: ref(true),
                expireDate: ref(''),
                expireTimestamp: ref(600),
                urlResult: ref(''),
                signMode: true
            },
            string: {
                expireMode: ref('日期时间选择模式'),
                expireTimestamp: ref('10分钟后过期'),
            }
        };
    },
    mounted() {
        this.form.expireDate = (new Date()).setDate((new Date()).getDate() + 1);
    },
    methods: {
        expireModeSwitch: function (status) {
            if (status) this.string.expireMode = "日期时间选择模式";
            else this.string.expireMode = "过期时间输入模式";
        },
        expireTimestampChange: function () {
            this.string.expireTimestamp = this.formatTime(this.form.expireTimestamp) + "后过期";
        },
        formatTime: function (seconds) {
            const units = {
                "年": 365 * 24 * 60 * 60,
                "月": 30 * 24 * 60 * 60,
                "日": 24 * 60 * 60,
                "小时": 60 * 60,
                "分钟": 60,
                "秒": 1
            };

            const result = [];

            for (const [unit, value] of Object.entries(units)) {
                const count = Math.floor(seconds / value);
                if (count > 0) {
                    result.push(`${count}${unit}`); // 可加 's' 变复数
                    seconds -= count * value;
                }
            }

            return result.length ? result.join('') : '0秒';
        },
        onSubmit: function () {
            if (!(this.form.url && this.form.key && this.form.uid)) {
                ElMessage.error('请输入完整的参数。');
                return;
            }

            this.constant.resultShow = false;
            this.constant.warningShow = false;
            this.constant.checkURLStatus = false;

            if (this.form.expireMode) {
                const now = new Date();
                this.form.expireTimestamp = Math.floor((this.form.expireDate - now) / 1000);
                this.expireTimestampChange();
            }

            // 是签名还是效验
            if (this.form.signMode) {
                const urlObj = new URL(this.form.url);
                const authKey = urlObj.searchParams.get('auth_key');

                if (authKey) {
                    ElMessage.error('您输入的链接貌似已经被签名，可以切换到效验模式进行效验。')
                    return;
                }

                this.form.urlResult = this.signURL(this.form.url, this.form.key, this.form.uid, this.form.expireTimestamp);

                // 保存参数
                localStorage.setItem('url', this.form.url);
                localStorage.setItem('key', this.form.key);
                localStorage.setItem('uid', this.form.uid);
            } else {
                const urlObj = new URL(this.form.url);
                const authKey = urlObj.searchParams.get('auth_key');

                if (!authKey) {
                    ElMessage.error('该链接不包含签名字段，请切换到签名模式进行签名。')
                    return;
                }
                this.form.urlResult = this.form.url;
            }

            const urlObj = new URL(this.form.urlResult);
            const authKey = urlObj.searchParams.get('auth_key');

            if (!authKey) {
                this.constant.checkURLStatus = true;
                this.$refs.URLStatusText.$el.textContent = `该链接不包含签名字段 ×`
                this.$refs.URLStatusText.$el.style.color = "red"
                return
            }

            if (this.form.signMode) {
                this.constant.resultShow = true;
                this.constant.countdownSecond = this.form.expireTimestamp;
            } else {
                this.constant.resultShow = true;
                const now = new Date();
                this.constant.countdownSecond = Math.floor(parseInt(authKey.split('-')[0]) - now / 1000);
            }

            // 开始倒计时
            if (!this.constant.countdownInterval) {
                this.countdownCallback()
                this.constant.countdownInterval = setInterval(this.countdownCallback, 1000);
            }

            this.checkURL(this.form.urlResult).then((res) => {

                if (!this.form.signMode) {
                    this.form.uid = authKey.split('-')[2];
                    this.form.expireMode = false;
                    this.form.expireTimestamp = Math.floor(parseInt(authKey.split('-')[0]) - (new Date()) / 1000);
                    this.expireTimestampChange();
                    // 静态效验
                    const urlObj = new URL(this.form.urlResult);
                    const baseUrl = `${urlObj.origin}${urlObj.pathname}`;
                    const signUrl = this.signURL(baseUrl, this.form.key, this.form.uid,
                        null, parseInt(authKey.split('-')[0]), parseInt(authKey.split('-')[1]));
                    if (signUrl !== this.form.urlResult) {
                        this.tipResultWarning("效验提示", "该链接无法被效验，因为您没有提供正确的签名密钥，但是您仍然可以查看服务器的效验结果。")
                    }
                }


                this.constant.checkURLStatus = true;
                if (res.success && res.response.ok) {
                    this.$refs.URLStatusText.$el.textContent = "链接签名有效 √"
                    this.$refs.URLStatusText.$el.style.color = "green"

                    // 静态校验
                    const currentTime = Math.floor(Date.now() / 1000);
                    if (currentTime > parseInt(authKey.split('-')[0])) {
                        this.tipResultWarning("失效提示", "虽然服务器响应该链接签名正确，但是此链接签名很可能已经过期。")
                    }

                } else if (res.success) {
                    if (400 <= res.response.status < 500) {
                        const currentTime = Math.floor(Date.now() / 1000);
                        if (currentTime < parseInt(authKey.split('-')[0])) {
                            this.tipResultWarning("失效提示", "服务器响应该签名是无效的，可能是你输入了错误的密钥或者 uid 进行签名。");
                        }
                        this.$refs.URLStatusText.$el.textContent = `链接签名无效(${res.response.status}) ×`;
                    } else
                        this.$refs.URLStatusText.$el.textContent = `服务器错误(${res.response.status}) ×`
                    this.$refs.URLStatusText.$el.style.color = "red"
                } else {
                    this.$refs.URLStatusText.$el.textContent = `链接验证失败网络请求失败 ×`
                    this.$refs.URLStatusText.$el.style.color = "red"
                }
            })
        },
        resultInputBoxClick: function () {
            const inputElement = this.$refs.resultInputBox.$el.querySelector('input');
            inputElement.select();
        },
        signURL: function (originURL, privateKey, uid, validDuration, tsI, rIntI) {
            const ts = tsI ? tsI : Math.floor((Date.now() + validDuration * 1000) / 1000);
            const rInt = rIntI ? rIntI : Math.floor(Math.random() * 1000000);
            const objURL = new URL(originURL);
            const authKey = `${ts}-${rInt}-${uid}-${crypto
                .MD5(`${decodeURIComponent(objURL.pathname)}-${ts}-${rInt}-${uid}-${privateKey}`)
                .toString()}`;
            objURL.searchParams.append('auth_key', authKey);
            return objURL.toString();
        },
        countdownCallback: function () {
            if (this.constant.countdownSecond <= 0) {
                this.constant.countdownSecondText = "已过期";
                clearInterval(this.constant.countdownInterval);
                return;
            }
            this.constant.countdownSecondText = this.formatTime(this.constant.countdownSecond--);
        },
        checkURL: async function (url) {
            // 在线检验链接是否有效
            try {
                const response = await fetch(url, {
                    method: 'HEAD',
                    mode: 'cors'
                });

                return {
                    success: true,
                    response: response
                };
            } catch (error) {
                return {
                    success: false,
                    response: error
                };
            }
        },
        tipResultWarning: function (title, text) {
            this.constant.warningShow = true;
            this.constant.warningTitle = title;
            this.constant.warningTip = text;
        },
        getPythonCode: function () {
            return `import hashlib
import time
import uuid
import urllib.parse

url = "要签名的链接"
uid = "账号UID"
primary_key = "你的密钥"
expored_time_sec = "链接有效秒数"

path = urllib.parse.urlparse(url).path
timestamp = int(time.time()) + expired_time_sec
random_uuid = str(uuid.uuid4()).replace('-', '')
unsigned_str = f'{path}-{timestamp}-{random_uuid}-{uid}-{primary_key}'
auth_key = f'{timestamp}-{random_uuid}-{uid}-' + hashlib.md5(unsigned_str.encode()).hexdigest()

print(url + '?auth_key=' + auth_key)`
        },
        getJavascriptCode: function () {
            return `const crypto = require('crypto-js');

function SignURL(originURL, privateKey, uid, validDuration) {
    const ts = Math.floor((Date.now() + validDuration) / 1000); // 有效时间戳，单位：秒
    const rInt = Math.floor(Math.random() * 1000000); // 随机正整数，这里生成一个最大值为1000000的随机整数
    const objURL = new URL(originURL);
    const authKey = \`\${ts}-\${rInt}-\${uid}-\${crypto
                .MD5(\`\${decodeURIComponent(objURL.pathname)}-\${ts}-\${rInt}-\${uid}-\${privateKey}\`)
                .toString()}\`;
    objURL.searchParams.append('auth_key', authKey);
    return objURL.toString();
}


const originURL = '签名链接'; // 待签名URL
const privateKey = '你的密钥';
const uid = 10; // 账号id
const validDuration = 15 * 60 * 1000; // 链接签名有效期，单位：毫秒

const newURL = SignURL(originURL, privateKey, uid, validDuration);
console.log(newURL);
`
        },
        getJavaCode: function () {
            return `import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.UUID;

public class DirectLink {

    // 123云盘中设置的密钥
    private static final String PRIVATE_KEY = "你的密钥";
    // 123云盘用户UID
    private static final long UID = 0;
    // 防盗链过期时间间隔(秒)
    private static final long EXPIRED_TIME_SEC = 3 * 60;
    // 下载地址
    private static final String DOWNLOAD_ADDRESS = "签名链接";

    private static String getSignedUrl(String path) {
        // 下载链接的过期时间戳（秒）
        long timestamp = new Date().getTime() / 1000 + EXPIRED_TIME_SEC;
        // 生成随机数（建议使用UUID，不能包含中划线（-））
        String randomUUID = UUID.randomUUID().toString().replaceAll("-", "");
        // 待签名字符串="URI-timestamp-rand-uid-PrivateKey" (注:URI是用户的请求对象相对地址，不包含参数)
        String unsignedStr = String.format("%s-%d-%s-%d-%s", path, timestamp, randomUUID, UID, PRIVATE_KEY);
        return DOWNLOAD_ADDRESS + "?auth_key=" + String.format("%d-%s-%d-", timestamp, randomUUID, UID) + md5sum(unsignedStr);
    }

    // MD5加密
    private static String md5sum(String unsignedStr) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] secretBytes = md5.digest(unsignedStr.getBytes());
            return bytesToHex(secretBytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return "";
    }

    // 二进制转为十六进制字符串
    public static String bytesToHex(byte[] bytes) {
        StringBuilder md5str = new StringBuilder();
        // 把数组每一字节换成16进制连成md5字符串
        int digital;
        for (byte aByte : bytes) {
            digital = aByte;

            if (digital < 0) {
                digital += 256;
            }
            if (digital < 16) {
                md5str.append("0");
            }
            md5str.append(Integer.toHexString(digital));
        }
        return md5str.toString().toLowerCase();
    }

    public static void main(String[] args) throws MalformedURLException {
        URL url = new URL(DOWNLOAD_ADDRESS);
        // 下载path
        String path = url.getPath();
        // 获得签名后的链接
        String signedUrl = getSignedUrl(path);
        System.out.println(signedUrl);
    }
}`;
        },
        getGoCode: function () {
            return `package main

import (
\t"crypto/md5"
\t"fmt"
\t"log"
\t"math/rand"
\t"net/url"
\t"time"
)

func SignURL(originURL, privateKey string, uid uint64, validDuration time.Duration) (newURL string, err error) {
\tvar (
\t\tts     = time.Now().Add(validDuration).Unix() // 有效时间戳
\t\trInt   = rand.Int()                           // 随机正整数
\t\tobjURL *url.URL
\t)
\tobjURL, err = url.Parse(originURL)
\tif err != nil {
\t\treturn "", err
\t}
\tauthKey := fmt.Sprintf("%d-%d-%d-%x", ts, rInt, uid, md5.Sum([]byte(fmt.Sprintf("%s-%d-%d-%d-%s",
\t\tobjURL.Path, ts, rInt, uid, privateKey))))
\tv := objURL.Query()
\tv.Add("auth_key", authKey)
\tobjURL.RawQuery = v.Encode()
\treturn objURL.String(), nil
}

func main() {
\tvar (
\t\toriginURL            = "签名的链接" // 待签名URL，即用户在123云盘直链空间目录下复制的直链url
\t\tprivateKey           = "鉴权密钥"   // 鉴权密钥，即用户在123云盘直链管理中设置的鉴权密钥
\t\tuid           uint64 = 0          // 账号id，即用户在123云盘个人中心页面所看到的账号id
\t\tvalidDuration        = time.Minute * 15     // 链接签名有效期
\t)
\tnewURL, err := SignURL(originURL, privateKey, uid, validDuration)
\tif err != nil {
\t\tlog.Fatal(err)
\t}
\tfmt.Println(newURL)
}
`;
        },
        getPHPCode: function () {
            return `<\?php
$url = '链接地址';
$private_key = '签名UID';
$uid = 0;  // 账户UID
$expire_time = time() + 30;   // 过期时间，这里是 30 秒
$rand_value = rand(0, 100000);
$parse_result = parse_url($url);
$request_path = rawurldecode($parse_result["path"]);
$sign = md5(sprintf("%s-%d-%d-%d-%s", $request_path, $expire_time, $rand_value, $uid, $private_key));
$wait = sprintf("%d-%d-%d-%s", $expire_time, $rand_value, $uid, $sign);
$result = $url . "?auth_key=" . $wait;
echo $result;`;
        }
    }
}
;
</script>

<style scoped>

.container {
    padding-top: 3rem;
    padding-left: 4rem;
    padding-right: 4rem;
    opacity: 0.97;
}

@media (max-width: 767px) {
    .container {
        padding-top: unset;
        padding-left: unset;
        padding-right: unset;
    }
}

.animate-h1 {

    /* 字体设置 */
    font-weight: 700;
    font-size: 2.8rem;
    color: #222;
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);

    /* 定位与内边距 */
    position: relative;
    display: inline-block;
    margin: 1.5rem 0;
    padding-bottom: 1rem;

    /* 动画设置 */
    animation: floating-cloud 6s ease-in-out infinite;
    transform-origin: 50% 100%;
}

/* 底部浅蓝色装饰条 */
.animate-h1::after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 70%;
    height: 0.5rem;
    background: #48c7ed82;
    border-radius: 1rem;
    box-shadow: 0 0.1rem 0.8rem rgba(91, 192, 222, 0.4);
}

/* 云朵漂浮动画 */
@keyframes floating-cloud {
    0%, 100% {
        transform: translateY(0) rotate(-1deg);
    }
    25% {
        transform: translateY(-6px) rotate(1.8deg);
    }
    50% {
        transform: translateY(3px) rotate(-2.2deg);
    }
    75% {
        transform: translateY(-4px) rotate(1deg);
    }
}

/* 在你的 CSS 文件中或 <style> 标签内 */
.highlight-container {
    max-width: 100%;
    overflow-x: auto;
    box-sizing: border-box;
}

.highlight-container pre,
.highlight-container code {
    /* 重置 highlight.js 的默认样式 */
    width: 100%;
    margin: 0;
    padding: 10px;
    box-sizing: border-box;
    white-space: pre-wrap; /* 确保长代码换行 */
}
</style>